/******************************************
Estacionamiento_implementacion_lista.java
Universidad del Valle de Guatemala
Algoritmos y Estructura de Datos
Autor:
    Martín Guzmán
Fecha: 15 de julio de 2009
Descripción: Clase que simula el funcionamiento
 * de un stack o pila utilizando listas encadenadas
 * dobles (debido a su facilidad de localizar el
 * último elemento de la pila)
*******************************************/
import java.util.ArrayList;
import java.lang.reflect.Array;
import java.lang.AssertionError;

public class Estacionamiento_implementacion_lista<G> implements Interfaz_stack<G> {
    private int disponibles;
    private final int max=10;
    Nodo<G> principio_lista;
    Nodo<G> ultimo_lista;

    //método constructor
    public Estacionamiento_implementacion_lista(){
        disponibles=10;
        principio_lista=null;
    }
    //regresa la cantidad de espacios disponibles en la pila
    public int getDisponibles() {
        return this.disponibles;
    }

    //método para ver si la pila está llena
    public boolean full() {
        boolean temporal=false;
        if(this.disponibles==0){
            temporal=true;
        }
        return temporal;
    }

    //método para ver si la pila está vacía
    public boolean empty() {
        boolean temporal=false;
        if(this.disponibles==10){
            temporal=true;
        }
        return temporal;
    }

    //método para sacar el último elemento de la pila
    public G pop() {
        assert this.disponibles!=10:"No se puede hacer un pop() sin antes haber metido nada...";
        if(this.empty()==true){ //revisa si está vacío
            System.out.println("*** Lo sentimos, no puede sacar el último elemento de la pila debido a que está vacía ****");
            return null;
        }
        //G return_value = null;
        
        Nodo<G> temporal = this.ultimo_lista.getAnterior_nodo();
        if(this.ultima_Posicion()==1){
            G return_value = null;
            this.ultimo_lista=temporal;
            this.disponibles++;
            return return_value;
        }
        else
        {
            G return_value = ultimo_lista.getValor();
            this.ultimo_lista=temporal;
            this.disponibles++;
            return return_value;
        }
        
    }
    
    //Devuelve la última posición que tiene un vehículo alamacenado
    public int ultima_Posicion(){
        int posicion=max-disponibles;
        return posicion;
    }

    //me retorna el índice en el que se encuentra el elemento dado
    //en caso de no encontrarse, retorna -1
    public int posicion_de(G Elemento_G){
        Nodo<G> temporal = this.principio_lista.getSiguiente_nodo();
        for(int i=1;i<=(this.max-this.disponibles);i++){
            if(temporal.getValor().toString().compareTo(Elemento_G.toString())==0)
            {
                return i-1;
            }
            temporal=temporal.getSiguiente_nodo();
        }
        return -1;
    }

    //método para que ingrese un nuevo elemento a la pila
    public void push(G Elemento_G) {
        assert this.disponibles!=0:"No se puede hacer un push() cuando ya hay 10 elementos metidos en la pila";
        if(this.disponibles!=0){ //el parqueo está lleno si disponibles=0
            if(this.empty()==true){ //el primer push
                principio_lista = new Nodo<G>(null,new Nodo<G>(Elemento_G,null,principio_lista),null);
                this.ultimo_lista=this.principio_lista.getSiguiente_nodo();
            }
            else
            {
                this.ultimo_lista.setSiguiente_nodo(new Nodo<G>(Elemento_G,null,ultimo_lista));
                this.ultimo_lista = this.ultimo_lista.getSiguiente_nodo();
            }
            disponibles-=1; //entró un elemento, por lo tanto hay uno menos disponible
        }
        else
        {
            //esto no va a dar porque cuando se llama al método se controla esto...
            System.out.println("******** Lo sentimos, ya no hay espacios disponibles *****");
        }
    }

    //método para ver el elemento del tope de la pila
    public G peek() {
        if (this.empty()==true)
        {
            return null;
        }
        G temporal = this.pop();
        this.push(temporal);
        return temporal;
    }

    public String toString(){
        String temporal="|";
        try{
            Nodo<G> temporal2 = this.principio_lista.getSiguiente_nodo();
            while (temporal2!=this.ultimo_lista.getSiguiente_nodo()){
                temporal=temporal+" "+temporal2.getValor().toString()+" |";
                temporal2=temporal2.getSiguiente_nodo();
            }
            for (int i=0;i<this.disponibles;i++){
                temporal+="--|";
            }
        }catch(Exception ex)
        {
            return "|--|--|--|--|--|--|--|--|--|--|";
        }
         
        return temporal;
    }

}